#include <openssl/hmac.h>
#include <openssl/ecdsa.h>
#include <openssl/ecdh.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <stdio.h>

#include "csvcert.h"

const char* curve_id_to_str[4] = {
    "CURVE_ID_TYPE_INVALID"
    "CURVE_ID_TYPE_P256",
    "CURVE_ID_TYPE_P384",
    "CURVE_ID_TYPE_SM2_256",
    };

typedef enum _key_usage {
    KEY_USAGE_TYPE_HRK     = 0,
    KEY_USAGE_TYPE_HSK     = 0x13,
    KEY_USAGE_TYPE_HKMSK   = 0x18,
    KEY_USAGE_TYPE_INVALID = 0x1000,
    KEY_USAGE_TYPE_MIN     = 0x1001,
    KEY_USAGE_TYPE_OCA     = 0x1001,
    KEY_USAGE_TYPE_PEK     = 0x1002,
    KEY_USAGE_TYPE_PDH     = 0x1003,
    KEY_USAGE_TYPE_CEK     = 0x1004,
    KEY_USAGE_TYPE_MAX     = 0x1004,
} key_usage_t;

const char* pub_key_usage_to_string(uint32_t pub_key_usage) {
    switch (pub_key_usage) {
    case KEY_USAGE_TYPE_HRK:
        return "KEY_USAGE_TYPE_HRK";
    case KEY_USAGE_TYPE_HSK:
        return "KEY_USAGE_TYPE_HSK";
    case KEY_USAGE_TYPE_INVALID:
        return "KEY_USAGE_TYPE_INVALID";
    case KEY_USAGE_TYPE_OCA:
        return "KEY_USAGE_TYPE_OCA";
    case KEY_USAGE_TYPE_PEK:
        return "KEY_USAGE_TYPE_PEK";
    case KEY_USAGE_TYPE_PDH:
        return "KEY_USAGE_TYPE_PDH";
    case KEY_USAGE_TYPE_CEK:
        return "KEY_USAGE_TYPE_CEK";
    default:
        return "UNKNOWN_KEY_USAGE_TYPE";
    }
}

const char* pub_key_algo_to_string(uint32_t pub_key_algo) {
    switch (pub_key_algo) {
    case CSV_SIG_ALGO_INVALID:
        return "SIG_ALGO_INVALID";
    case CSV_SIG_ALGO_RSA_SHA256:
        return "SIG_ALGO_RSA_SHA256";
    case CSV_SIG_ALGO_ECDSA_SHA256:
        return "SIG_ALGO_ECDSA_SHA256";
    case CSV_SIG_ALGO_ECDH_SHA256:
        return "SIG_ALGO_ECDH_SHA256";
    case CSV_SIG_ALGO_TYPE_SM2_SA:
        return "SIG_ALGO_TYPE_SM2_SA";
    case CSV_SIG_ALGO_TYPE_SM2_DH:
        return "SIG_ALGO_TYPE_SM2_DH";
    case CSV_SIG_ALGO_RSA_SHA384:
        return "SIG_ALGO_RSA_SHA384";
    case CSV_SIG_ALGO_ECDSA_SHA384:
        return "SIG_ALGO_ECDSA_SHA384";
    case CSV_SIG_ALGO_ECDH_SHA384:
        return "SIG_ALGO_ECDH_SHA384";
    default:
        return "UNKNOWN_SIG_ALGO";
    }
}

/**
 * @brief  Print a CSV certificate in a readable ASCII format
 *
 * @param  [in]  cert     The source certificate to be printed
 * @param  [out] out_str  If provided, the text output will be stored in out_str
 *                        instead of being printed to the screen
 *
 * @returns None
 */
void print_csv_cert_readable(const csv_cert* cert, char* out_str) {
    char out[sizeof(csv_cert) * 3 + 2500];  // 2 chars per byte + 1 space + ~500 extra chars for text

    // Format version, api_major, and api_minor
    sprintf(out, "%-15s%08x\n", "Version:", cert->version);                    // uint32_t
    sprintf(out + strlen(out), "%-15s%02x\n", "api_major:", cert->api_major);  // uint8_t
    sprintf(out + strlen(out), "%-15s%02x\n", "api_minor:", cert->api_minor);  // uint8_t

    // Format pub_key_usage and pub_key_algo
    sprintf(out + strlen(out), "pub_key_usage: %s\n", pub_key_usage_to_string(cert->pub_key_usage));  // uint32_t
    sprintf(out + strlen(out), "pub_key_algo: %s\n", pub_key_algo_to_string(cert->pub_key_algo));      // uint32_t
    sprintf(out + strlen(out), "\n");

    // Format Pubkey section
    sprintf(out + strlen(out), "%-15s\n", "Pubkey:");  // csv_pubkey
    sprintf(out + strlen(out), "Curve: %s\n", curve_id_to_str[((uint8_t*)&cert->pub_key)[0] - 1]);

    // Format Qx and Qy
    sprintf(out + strlen(out), "%-15s\n", "Qx:");
    for (size_t i = 0; i < 32; i++) {  //bytes to uint8
        sprintf(out + strlen(out), "%02X ", ((uint8_t*)&cert->pub_key.sm2.qx)[i]);
    }
    sprintf(out + strlen(out), "\n");

    sprintf(out + strlen(out), "%-15s\n", "Qy:");
    for (size_t i = 0; i < 32; i++) {  //bytes to uint8
        sprintf(out + strlen(out), "%02X ", ((uint8_t*)&cert->pub_key.sm2.qy)[i]);
    }
    sprintf(out + strlen(out), "\n");

    // Format Userid
    sprintf(out + strlen(out), "%-15s", "Userid:");  //bytes to uint8
    sprintf(out + strlen(out), "%s ", cert->pub_key.sm2.userid.uid);
    sprintf(out + strlen(out), "\n");

    sprintf(out + strlen(out), "\n");

    // Format sig_1_usage and sig_1_algo
    sprintf(out + strlen(out), "sig_1_usage: %s \n", pub_key_usage_to_string(cert->sig_1_usage));  // uint32_t
    sprintf(out + strlen(out), "sig_1_algo: %s \n", pub_key_algo_to_string(cert->sig_1_algo));     // uint32_t
    sprintf(out + strlen(out), "%-15s\n", "Sig1:");                                                // csv_sig

    // Format Sig1 R and S
    sprintf(out + strlen(out), "%-15s\n", "R:");
    for (size_t i = 0; i < 32; i++) {  //bytes to uint8
        sprintf(out + strlen(out), "%02X ", cert->sig_1.ecdsa.r[i]);
    }
    sprintf(out + strlen(out), "\n");

    sprintf(out + strlen(out), "%-15s\n", "S:");
    for (size_t i = 0; i < 32; i++) {  //bytes to uint8
        sprintf(out + strlen(out), "%02X ", cert->sig_1.ecdsa.s[i]);
    }
    sprintf(out + strlen(out), "\n");
    sprintf(out + strlen(out), "\n");

    // Format sig_2_usage and sig_2_algo
    sprintf(out + strlen(out), "sig_2_usage:%s \n", pub_key_usage_to_string(cert->sig_2_usage));  // uint32_t
    sprintf(out + strlen(out), "sig_2_algo:%s  \n", pub_key_algo_to_string(cert->sig_2_algo));    // uint32_t
    sprintf(out + strlen(out), "%-15s\n", "Sig2:");                                               // csv_sig

    // Format Sig2 R and S
    sprintf(out + strlen(out), "%-15s\n", "R:");
    for (size_t i = 0; i < 32; i++) {  //bytes to uint8
        sprintf(out + strlen(out), "%02X ", cert->sig_2.ecdsa.r[i]);
    }
    sprintf(out + strlen(out), "\n");

    sprintf(out + strlen(out), "%-15s\n", "S:");
    for (size_t i = 0; i < 32; i++) {  //bytes to uint8
        sprintf(out + strlen(out), "%02X ", cert->sig_2.ecdsa.s[i]);
    }
    sprintf(out + strlen(out), "\n");

    // Copy output to out_str or print to console
    if (strcmp(out_str, "NULL") == 0) {
        printf("%s\n", out);
    } else {
        strcat(out_str, out);
    }
}

/**
 * @brief  Print the contents of a CSV certificate as hex bytes
 *
 * @param  [in] cert  The source certificate to be printed
 *
 * @returns None
 */
void print_csv_cert_hex(const csv_cert* cert)
{
    printf("Printing cert as hex...\n");
    for (size_t i = 0; i < (size_t)(sizeof(csv_cert)); i++) {  // bytes to uint8
        printf("%02X ", ((uint8_t*)cert)[i]);
    }
    printf("\n");
}

/**
 * @brief  Print the contents of a digest as hex bytes
 *
 * @param  [in] dgst  The source digest data to be printed
 * @param  [in] len   The length of the digest data in bytes
 *
 * @returns None
 */
void print_dgst(uint8_t *dgst, size_t len) {
    printf("dgst: ");
    for (size_t i = 0; i < len; i++) {
        printf("%02X ", dgst[i]);
    }
    printf("\n");
}

/**
 * @brief  Reverse the order of bytes in a given buffer
 *
 * @param  [in,out] bytes  Pointer to the buffer containing bytes to be reversed
 * @param  [in]     size   The number of bytes in the buffer
 *
 * @returns Success: 0, Failure: -1
 */
int reverse_bytes(uint8_t* bytes, size_t size)
{
    uint8_t* start = bytes;
    uint8_t* end   = bytes + size - 1;

    if (!bytes)
        return -1;

    while (start < end) {
        uint8_t byte = *start;
        *start       = *end;
        *end         = byte;
        start++;
        end--;
    }

    return 0;
}

/**
 * @brief  Read a private key PEM file and store it in an EC_KEY structure
 *
 * @param  [in]  file_name   The name of the PEM file to be read
 * @param  [out] ec_priv_key Pointer to an EC_KEY where the private key will be stored
 *
 * @returns None (Caller must free the allocated EC_KEY)
 */
void read_priv_key_pem_into_eckey(const char *file_name, EC_KEY** ec_priv_key)
{
    do {
        // New up the EC_KEY with the EC_GROUP
        *ec_priv_key = EC_KEY_new_by_curve_name(NID_sm2p256v1);

        // Read in the private key file into EVP_PKEY
        FILE* pFile = fopen(file_name, "r");
        if (!pFile)
            break;
        *ec_priv_key = PEM_read_ECPrivateKey(pFile, NULL, NULL, NULL);
        fclose(pFile);
        if (!ec_priv_key)
            break;
    } while (0);
}

/**
 * @brief  Read a private key PEM file and convert an EC key to an EVP key
 *
 * @param  [in]  file_name     The name of the PEM file to be read
 * @param  [out] evp_priv_key  Pointer to an EVP_PKEY where the private key will be stored
 *
 * @returns Success: 0, Failure: -1
 *
 * @note This function allocates a new EVP_PKEY, which also manages the associated EC_KEY.
 *       The caller must free the EVP_PKEY to avoid memory leaks.
 */

int read_priv_key_pem_into_evpkey(const char *file_name, EVP_PKEY** evp_priv_key)
{
    EC_KEY* ec_privkey = NULL;

    // New up the EVP_PKEY
    if (!(*evp_priv_key = EVP_PKEY_new()))
        return -1;

    // Read in the file as an EC key
    read_priv_key_pem_into_eckey(file_name, &ec_privkey);

    // Convert EC key to EVP_PKEY
    // This function links EVP_pubKey to EC_pubKey, so when EVP_pubKey
    //  is freed, EC_pubKey is freed. We don't want the user to have to
    //  manage 2 keys, so just return EVP_PKEY and make sure user free's it
    if (EVP_PKEY_assign_EC_KEY(*evp_priv_key, ec_privkey) != 1)
        return -1;

    return 0;
}


/**
 * @brief  Convert an EVP_PKEY to a csv_cert format
 *
 * @param  [out] cert        Pointer to the output csv_cert where the public key will be stored
 * @param  [in]  evp_pubkey  Pointer to the input EVP_PKEY containing the public key
 *
 * @returns Success: STATUS_SUCCESS, Failure: ERROR_INVALID_CERTIFICATE
 *
 * @note This function allocates memory for an EC_KEY, which must be freed by the caller
 *       using EC_KEY_free(). It extracts the EC public key from EVP_PKEY, verifies it,
 *       and stores its x and y coordinates in the certificate in little-endian format.
 */
CSV_ERROR_CODE convert_pubkey_to_cert(csv_cert* cert, EVP_PKEY* evp_pubkey)
{
    if (!cert)
        return ERROR_INVALID_CERTIFICATE;

    CSV_ERROR_CODE cmd_ret   = ERROR_INVALID_CERTIFICATE;
    EC_KEY*        ec_pubkey = NULL;
    BIGNUM*        x_bignum  = NULL;
    BIGNUM*        y_bignum  = NULL;
    BIGNUM*        modulus   = NULL;
    BIGNUM*        pub_exp   = NULL;

    do {

        EC_GROUP* ec_group = EC_GROUP_new_by_curve_name(NID_sm2p256v1);

        // Set the curve parameter of the cert's pubkey
        cert->pub_key.sm2.curve = CURVE_ID_TYPE_SM2_256;

        // Create/allocate memory for an EC_KEY object using the NID above
        if (!(ec_pubkey = EC_KEY_new_by_curve_name(NID_sm2p256v1)))
            break;

        // Pull the EC_KEY from the EVP_PKEY
        ec_pubkey = EVP_PKEY_get1_EC_KEY(evp_pubkey);

        // Make sure the key is good
        if (EC_KEY_check_key(ec_pubkey) != 1)
            break;

        // Get the EC_POINT from the public key
        const EC_POINT* pub = EC_KEY_get0_public_key(ec_pubkey);

        // New up the BIGNUMs
        BIGNUM* x_bignum = BN_new();
        BIGNUM* y_bignum = BN_new();

        // Get the x and y coordinates from the EC_POINT and store as separate BIGNUM objects
        if (!EC_POINT_get_affine_coordinates_GFp(ec_group, pub, x_bignum, y_bignum, NULL))
            break;

        // Store the x and y components into the cert. The values in the
        // BIGNUM are stored as big-endian, so must reverse bytes before
        // storing in CSV certificate as little-endian
        if (BN_bn2lebinpad(x_bignum, (unsigned char*)cert->pub_key.sm2.qx, sizeof(cert->pub_key.ecdh.qx)) <= 0)
            break;
        if (BN_bn2lebinpad(y_bignum, (unsigned char*)cert->pub_key.sm2.qy, sizeof(cert->pub_key.ecdh.qy)) <= 0)
            break;

        if (!evp_pubkey)
            break;

        cmd_ret = STATUS_SUCCESS;
    } while (0);

    // Free memory if it was allocated
    BN_free(y_bignum);  // If NULL, does nothing
    BN_free(x_bignum);
    BN_free(modulus);
    BN_free(pub_exp);

    return cmd_ret;
}

/**
 * @brief  Signs a certificate using the provided private key (sig1 signature)
 *
 * @param  [out] m_child_cert  Pointer to the certificate to be signed
 * @param  [in]  version       Certificate version
 * @param  [in]  pub_key_usage Public key usage type
 * @param  [in]  pub_key_algo  Public key algorithm identifier
 * @param  [in]  priv_evp_key  Pointer to the private key used for signing
 * @param  [in]  sig_1_usage   Signature usage type for sig1
 * @param  [in]  sig_1_algo    Signature algorithm identifier for sig1
 * @param  [in]  userid        Identifier used in the signing process
 *
 * @returns Success: 0, Failure: non-zero error code
 *
 * @note This function signs the certificate's sig1 field using the provided
 *       private key and stores the signature in little-endian format.
 */
int sign_with_key_in_sig1(csv_cert *m_child_cert, uint32_t version, uint32_t pub_key_usage,
                          uint32_t pub_key_algo, EVP_PKEY** priv_evp_key,
                          uint32_t sig_1_usage, uint32_t sig_1_algo, const char* userid)
{
    EC_KEY*         priv_ec_key = NULL;
    uint8_t         dsig[512];
    unsigned long   sig_len = sizeof(sm2_signature_t);
    uint8_t         dgst[HASH_BLOCK_LEN];
    const uint8_t*  p       = dsig;
    int             int_ret = 0;
    const BIGNUM *  br, *bs;
    ECDSA_SIG*      es = NULL;
    int             ret_len;
    sm2_signature_t sm2_sig;

    do {
        // The constructor defaults all member vars, and the user can change them
        memset(&m_child_cert->sig_1, 0, sizeof(csv_sig));
        m_child_cert->version       = version;
        m_child_cert->pub_key_usage = pub_key_usage;
        m_child_cert->pub_key_algo  = pub_key_algo;

        m_child_cert->sig_1_usage   = sig_1_usage;  // Parent cert's sig
        m_child_cert->sig_1_algo    = sig_1_algo;

        priv_ec_key = EC_KEY_new_by_curve_name(NID_sm2p256v1);

        priv_ec_key = EVP_PKEY_get1_EC_KEY(*priv_evp_key);
        if (!priv_ec_key)
            break;
        int_ret = SM2_compute_message_digest(EVP_sm3(), EVP_sm3(), (uint8_t*)m_child_cert, 16 + 1028, userid, strlen(userid), dgst, &sig_len, priv_ec_key);
        int_ret = SM2_sign(NID_undef, dgst, (int)sig_len, dsig, (unsigned int*)&sig_len, priv_ec_key);

        /*output signature*/
        es = d2i_ECDSA_SIG(NULL, &p, sig_len);

        ECDSA_SIG_get0(es, &br, &bs);

        ret_len = BN_bn2bin(br, dsig);
        memset(&sm2_sig, 0, SM2_KEY_SIZE * 2);
        memcpy((unsigned char*)&sm2_sig + SM2_KEY_SIZE - ret_len, dsig, ret_len);

        ret_len = BN_bn2bin(bs, dsig);
        memcpy((unsigned char*)&sm2_sig + SM2_KEY_SIZE * 2 - ret_len, dsig, ret_len);
        csv_signature_t* csv_sig;
        csv_sig = (csv_signature_t*)&m_child_cert->sig_1;
        memcpy(csv_sig->r, sm2_sig.r, 32);
        memcpy(csv_sig->s, sm2_sig.s, 32);
        reverse_bytes(csv_sig->r, 32);
        reverse_bytes(csv_sig->s, 32);
    } while (0);

    // Free memory
    EC_KEY_free(priv_ec_key);

    return int_ret;
}

/**
 * @brief  Signs a certificate using the provided private key (sig2 signature)
 *
 * @param  [out] m_child_cert  Pointer to the certificate to be signed
 * @param  [in]  version       Certificate version
 * @param  [in]  pub_key_usage Public key usage type
 * @param  [in]  pub_key_algo  Public key algorithm identifier
 * @param  [in]  priv_evp_key  Pointer to the private key used for signing
 * @param  [in]  sig_2_usage   Signature usage type for sig2
 * @param  [in]  sig_2_algo    Signature algorithm identifier for sig2
 * @param  [in]  userid        Identifier used in the signing process
 *
 * @returns Success: 0, Failure: non-zero error code
 *
 * @note This function signs the certificate's sig2 field using the provided
 *       private key and stores the signature in little-endian format. If
 *       "NULL" is passed as userid, a default "OCA_USER_ID" is used.
 */
int sign_with_key_in_sig2(csv_cert *m_child_cert, uint32_t version, uint32_t pub_key_usage,
                          uint32_t pub_key_algo, EVP_PKEY** priv_evp_key,
                          uint32_t sig_2_usage, uint32_t sig_2_algo, const char* userid)
{
    EC_KEY*         priv_ec_key = NULL;
    uint8_t         dsig[512];
    unsigned long   sig_len = sizeof(sm2_signature_t);
    uint8_t         dgst[HASH_BLOCK_LEN];
    const uint8_t*  p       = dsig;
    int             int_ret = 0;
    const BIGNUM *  br, *bs;
    ECDSA_SIG*      es = NULL;
    int             ret_len;
    sm2_signature_t sm2_sig;

    do {
        // The constructor defaults all member vars, and the user can change them
        memset(&m_child_cert->sig_2, 0, sizeof(csv_sig));
        m_child_cert->version       = version;
        m_child_cert->pub_key_usage = pub_key_usage;
        m_child_cert->pub_key_algo  = pub_key_algo;

        m_child_cert->sig_2_usage   = sig_2_usage;  // Parent cert's sig
        m_child_cert->sig_2_algo    = sig_2_algo;

        priv_ec_key = EC_KEY_new_by_curve_name(NID_sm2p256v1);

        priv_ec_key = EVP_PKEY_get1_EC_KEY(*priv_evp_key);
        if (!priv_ec_key)
            break;

        if (!strcmp(userid, "NULL")) {
            int_ret = SM2_compute_message_digest(EVP_sm3(), EVP_sm3(), (uint8_t*)m_child_cert, 16 + 1028, "OCA_USER_ID", 11, dgst, &sig_len, priv_ec_key);
        } else {
            int_ret = SM2_compute_message_digest(EVP_sm3(), EVP_sm3(), (uint8_t*)m_child_cert, 16 + 1028, userid, strlen(userid), dgst, &sig_len, priv_ec_key);
        }

        int_ret = SM2_sign(NID_undef, dgst, (int)sig_len, dsig, (unsigned int*)&sig_len, priv_ec_key);
        /*output signature*/
        es = d2i_ECDSA_SIG(NULL, &p, sig_len);

        ECDSA_SIG_get0(es, &br, &bs);

        ret_len = BN_bn2bin(br, dsig);
        memset(&sm2_sig, 0, SM2_KEY_SIZE * 2);
        memcpy((unsigned char*)&sm2_sig + SM2_KEY_SIZE - ret_len, dsig, ret_len);

        ret_len = BN_bn2bin(bs, dsig);
        memcpy((unsigned char*)&sm2_sig + SM2_KEY_SIZE * 2 - ret_len, dsig, ret_len);
        csv_signature_t* csv_sig;
        csv_sig = (csv_signature_t*)&m_child_cert->sig_2;

        memcpy(csv_sig->r, sm2_sig.r, 32);
        memcpy(csv_sig->s, sm2_sig.s, 32);
        reverse_bytes(csv_sig->r, 32);
        reverse_bytes(csv_sig->s, 32);
    } while (0);

    // Free memory
    EC_KEY_free(priv_ec_key);
    return int_ret;
}

/**
 * @brief  Creates an Owner Certificate Authority (OCA) certificate using an existing ECDH key pair.
 *
 * @param  [in]  oca_key_pair  Pointer to the input public/private key pair used to populate and sign the certificate.
 * @param  [in]  api_major     The major API version obtained from a PlatformStatus command.
 * @param  [in]  api_minor     The minor API version obtained from a PlatformStatus command.
 * @param  [in]  userid        User identifier to be included in the certificate.
 *
 * @returns A pointer to the newly created csv_cert structure, or NULL if an error occurs.
 *
 * @note This function allocates memory for the csv_cert structure, which must be freed by the caller.
 *       It populates the certificate fields and optionally signs it with the provided private key.
 *       If "NULL" is passed as userid, a default "OCA_USER_ID" is used.
 */
csv_cert* create_oca_cert(EVP_PKEY** oca_key_pair, uint8_t api_major, uint8_t api_minor, const char *userid)
{

    csv_cert       *m_child_cert = NULL;

    if (!oca_key_pair)
        return NULL;
    m_child_cert = calloc(1, sizeof(csv_cert));
    if (!m_child_cert) {
        return NULL;
    }
    do {

        m_child_cert->version       = CSV_CERT_MAX_VERSION;
        m_child_cert->api_major     = api_major;
        m_child_cert->api_minor     = api_minor;
        m_child_cert->pub_key_usage = CSV_USAGE_OCA;
        m_child_cert->pub_key_algo  = CSV_SIG_ALGO_TYPE_SM2_SA;
        m_child_cert->sig_1_usage   = CSV_USAGE_OCA;
        m_child_cert->sig_1_algo    = CSV_SIG_ALGO_TYPE_SM2_SA;
        m_child_cert->sig_2_usage   = CSV_USAGE_INVALID;
        m_child_cert->sig_2_algo    = CSV_SIG_ALGO_INVALID;
        if (!strcmp(userid, "NULL")) {
            m_child_cert->pub_key.sm2.userid.len = 11;
            memcpy(m_child_cert->pub_key.sm2.userid.uid, "OCA_USER_ID", 11);
        } else {
            m_child_cert->pub_key.sm2.userid.len = (uint16_t)strlen(userid);
            memcpy(m_child_cert->pub_key.sm2.userid.uid, userid, strlen(userid));
        }
        // Set the pubkey portion of the cert
        if (convert_pubkey_to_cert(m_child_cert, *oca_key_pair) != STATUS_SUCCESS)
            break;

        // Set the rest of the params and sign the signature with the newly
        // generated GODH privkey
        // Technically this step is not necessary, as the firmware doesn't
        // validate the GODH signature
        if (!sign_with_key_in_sig1(m_child_cert, CSV_CERT_MAX_VERSION, CSV_USAGE_OCA, CSV_SIG_ALGO_TYPE_SM2_SA, oca_key_pair, CSV_USAGE_OCA, CSV_SIG_ALGO_TYPE_SM2_SA, (const char*)m_child_cert->pub_key.sm2.userid.uid))
            break;

    } while (0);

    return m_child_cert;
}
